package com.sdp.flow.db.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.Gateway;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdp.flow.db.entity.ActHiComment;
import com.sdp.flow.db.entity.ActTemplateInfo;
import com.sdp.flow.db.service.IActHiCommentService;
import com.sdp.flow.db.service.IActRuTaskService;
import com.sdp.flow.db.service.IActTemplateInfoService;
import com.sdp.flow.db.service.IWorkflowService;
import com.sdp.flow.dto.FlowParam;
import com.sdp.flow.dto.TodoTaskView;
import com.sdp.flow.utils.FlowConstants;

@Service
public class WorkflowServiceImpl implements IWorkflowService {
	
	@Autowired
    protected IActTemplateInfoService templateInfoService;
	
	@Autowired
	private RuntimeService runtimeService;
	
	@Autowired
	private TaskService taskService;
	
	
	@Autowired
	private RepositoryService repositoryService;
	
	
	@Autowired
	private IActHiCommentService hiCommentService;
	
	@Autowired
	private IActRuTaskService ruTaskService;
	
	@Override
	public String startFlow(FlowParam flowParam) {
		if (flowParam != null && !StringUtils.isEmpty(flowParam.getTemplateId()) && !StringUtils.isEmpty(flowParam.getBizId())) {
			QueryWrapper<ActTemplateInfo> queryWrapper = new QueryWrapper<>();
			queryWrapper.lambda().eq(ActTemplateInfo::getKeyId, flowParam.getTemplateId());
			ActTemplateInfo model = templateInfoService.getOne(queryWrapper, false);
			if (model != null) {
				//流程启动额外参数
				Map<String, Object> variables = null;
				if (flowParam.getVariableMap() != null) {
					variables = flowParam.getVariableMap();
				} else {
					variables = new HashMap<>();
				}
				
				// 获取流程构造器，设置流程实例冗余信息
			    ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
			    processInstanceBuilder.name(model.getTemplateName())
			    	.businessKey(flowParam.getBizId())
			    	.processDefinitionKey(flowParam.getTemplateId())
			    	.variables(variables);
			    ProcessInstance processInstance = processInstanceBuilder.start();
			    return processInstance.getId();
			}
		}
		return null;
	}

	@Transactional
	@Override
	public String startFlowAndCommit(FlowParam flowParam) {
		if (flowParam != null && !StringUtils.isEmpty(flowParam.getTemplateId()) && !StringUtils.isEmpty(flowParam.getBizId())) {
			QueryWrapper<ActTemplateInfo> queryWrapper = new QueryWrapper<>();
			queryWrapper.lambda().eq(ActTemplateInfo::getKeyId, flowParam.getTemplateId());
			ActTemplateInfo model = templateInfoService.getOne(queryWrapper, false);
			if (model != null) {
				//流程启动额外参数
				Map<String, Object> variables = new HashMap<>();
				if (flowParam.getVariableMap() != null) {
					for (String key : flowParam.getVariableMap().keySet()) {
						if (FlowConstants.FLOW_ASSIGN_PERSON_KEY.equals(key)) {
							//流程发起的处理人只能是当前登录人，如果参数map中传递的有处理人字段，一定是指派的下一环节处理人
							variables.put(FlowConstants.FLOW_ASSIGN_PERSON_KEY, flowParam.getUserId());
						} else {
							variables.put(key, flowParam.getVariableMap().get(key));
						}
					}
				}
				if (!variables.containsKey(FlowConstants.FLOW_ASSIGN_PERSON_KEY)) {
					variables.put(FlowConstants.FLOW_ASSIGN_PERSON_KEY, flowParam.getUserId());
				}
				if (!StringUtils.isEmpty(flowParam.getUserId())) {//设置流程启动人
					Authentication.setAuthenticatedUserId(flowParam.getUserId());
				}
				
				// 获取流程构造器，设置流程实例冗余信息
			    ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
			    processInstanceBuilder.name(model.getTemplateName())
			    	.businessKey(flowParam.getBizId())
			    	.processDefinitionKey(flowParam.getTemplateId())
			    	.variables(variables);
			    ProcessInstance processInstance = processInstanceBuilder.start();
			    //清理流程启动人
			    Authentication.setAuthenticatedUserId(null);
			    //查找第一个任务并提交
			    Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
			    //提交任务时，使用外部传递的参数map对象
			    
			    //flowParam.getVariableMap().put(FlowConstants.FLOW_ASSIGN_PERSON_LIST_KEY, Arrays.asList(new String[]{"qcy", "zsp"}));
			    
			    taskService.complete(task.getId(), flowParam.getVariableMap());
			    return processInstance.getId();
			}
		}
		return null;
	}

	@Override
	public void stopFlow(String instanceId, String reason) {
		runtimeService.deleteProcessInstance(instanceId, reason);
	}

	@Override
	public void claimTask(String taskId, String userId) {
		taskService.claim(taskId, userId);
	}

	@Override
	public void unclaimTask(String taskId) {
		//处理人置空
		taskService.claim(taskId, null);
	}

	@Transactional
	@Override
	public void commitTask(FlowParam flowParam) {
		if (!StringUtils.isEmpty(flowParam.getUserId()) && !StringUtils.isEmpty(flowParam.getTaskId())) {
			Task task = taskService.createTaskQuery().taskId(flowParam.getTaskId()).singleResult();
			if (task != null) {
				if (StringUtils.isEmpty(task.getAssignee())) {
					taskService.claim(flowParam.getTaskId(), flowParam.getUserId());
					//保险起见拾取任务之后用当前登录人重新查一下任务
					task = taskService.createTaskQuery().taskAssignee(flowParam.getUserId()).singleResult();
				} else if (!flowParam.getUserId().equals(task.getAssignee())) {
					//任务处理人与当前userId不相同，不能提交任务
					throw new RuntimeException("userId= {" + flowParam.getUserId() + "}的人员无权限办理此任务!");
				}
				Map<String, Object> variables = null;
				if (flowParam.getVariableMap() != null) {
					variables = flowParam.getVariableMap();
				} else {
					variables = new HashMap<>();
				}

				//如果有审批意见需要提交
				if (flowParam.getOpinionMap() != null && flowParam.getOpinionMap().size() > 0) {
					for (String type : flowParam.getOpinionMap().keySet()) {
						taskService.addComment(task.getId(), task.getProcessInstanceId(), type, flowParam.getOpinionMap().get(type));
					}
					UpdateWrapper<ActHiComment> updateWrapper = new UpdateWrapper<>();
					updateWrapper.lambda().eq(ActHiComment::getTaskId, task.getId())
						.set(ActHiComment::getUserId, flowParam.getUserId())
						.set(ActHiComment::getUserName, StringUtils.isEmpty(variables.get("userName"))?"":variables.get("userName").toString())
						.set(ActHiComment::getUserAvatar, StringUtils.isEmpty(variables.get("userAvatar"))?"":variables.get("userAvatar").toString())
						.set(ActHiComment::getUserSign, StringUtils.isEmpty(variables.get("userSign"))?"":variables.get("userSign").toString())
						.set(ActHiComment::getIsPass, StringUtils.isEmpty(variables.get("isPass"))?"":variables.get("isPass").toString());
					hiCommentService.update(updateWrapper);
				}
				taskService.complete(task.getId(), variables);
			} else {
				throw new RuntimeException("taskId={" + flowParam.getTaskId() + "}的任务未找到");
			}
			
		} else {
			throw new RuntimeException("userId或taskId不能为空");
		}
	}

	@Override
	public List<TodoTaskView> getTodoTaskListByUserId(String systemNo, String userId) {
		if (!StringUtils.isEmpty(userId)) {
			QueryWrapper<TodoTaskView> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("a.ASSIGNEE_", userId)
			.or(qw -> qw.isNull("a.ASSIGNEE_").eq("b.USER_ID_", userId));
			if (!StringUtils.isEmpty(systemNo)) {
				queryWrapper.eq("c.SYSTEM_NO", systemNo);
			}
			return ruTaskService.viewList(queryWrapper,null);
		}
		return null;
	}

	@Override
	public IPage<TodoTaskView> getTodoTaskPageByUserId(String systemNo, String userId, Integer pageNum, Integer pageSize) {
		if (!StringUtils.isEmpty(userId) && pageNum != null && pageSize != null) {
			Page<TodoTaskView> page = new Page<TodoTaskView>(pageNum, pageSize);
			QueryWrapper<TodoTaskView> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("a.ASSIGNEE_", userId)
			.or(qw -> qw.isNull("a.ASSIGNEE_").eq("b.USER_ID_", userId));
			if (!StringUtils.isEmpty(systemNo)) {
				queryWrapper.eq("c.SYSTEM_NO", systemNo);
			}
			return ruTaskService.viewPage(page, queryWrapper,null);
		}
		return null;
	}

	@Override
	public TodoTaskView getTodoTaskByTaskId(String taskId) {
		if (!StringUtils.isEmpty(taskId)) {
			Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			TodoTaskView taskView = new TodoTaskView();
			taskView.setAssignee(task.getAssignee());
			taskView.setCategory(task.getCategory());
			if (task.getClaimTime() != null) {
				taskView.setClaimTime(LocalDateTime.ofInstant(task.getClaimTime().toInstant(), ZoneId.systemDefault()));
			}
			if (task.getCreateTime() != null) {
				taskView.setCreateTime(LocalDateTime.ofInstant(task.getCreateTime().toInstant(), ZoneId.systemDefault()));
			}
			taskView.setDelegation(task.getDelegationState().toString());
			taskView.setDescription(task.getDescription());
			if (task.getDueDate() != null) {
				taskView.setDueDate(LocalDateTime.ofInstant(task.getDueDate().toInstant(), ZoneId.systemDefault()));
			}
			taskView.setExecutionId(task.getExecutionId());
			taskView.setFormKey(task.getFormKey());
			taskView.setId(task.getId());
			if (task.getIdentityLinks() != null) {
				taskView.setIdLinkCount(task.getIdentityLinks().size());
			}
			//taskView.setIsCountEnabled(task.);
			taskView.setName(task.getName());
			taskView.setOwner(task.getOwner());
			taskView.setParentTaskId(task.getParentTaskId());
			taskView.setPriority(task.getPriority());
			taskView.setProcDefId(task.getProcessDefinitionId());
			taskView.setProcInstId(task.getProcessInstanceId());
			taskView.setPropagatedStageInstId(task.getPropagatedStageInstanceId());
			//taskView.setRev(task.r);
			taskView.setScopeDefinitionId(task.getScopeDefinitionId());
			taskView.setScopeId(task.getScopeId());
			taskView.setScopeType(task.getScopeType());
			taskView.setSubScopeId(task.getSubScopeId());
			//taskView.setSubTaskCount(task.getsu);
			//taskView.setSuspensionState(task.getsus);
			if (task.getTaskLocalVariables() != null) {
				taskView.setVarCount(task.getTaskLocalVariables().size());
			}
			taskView.setTenantId(task.getTenantId());
			taskView.setTaskDefId(task.getTaskDefinitionId());
			taskView.setTaskDefKey(task.getTaskDefinitionKey());
			//处理类型
			//taskView.setType(type);
			//查询流程模板信息
			QueryWrapper<ActTemplateInfo> queryWrapper = new QueryWrapper<>();
			queryWrapper.lambda().eq(ActTemplateInfo::getProcDefId, task.getProcessDefinitionId());
			ActTemplateInfo templateInfo = templateInfoService.getOne(queryWrapper, false);
			if (templateInfo != null) {
				taskView.setTemplateName(templateInfo.getTemplateName());
				taskView.setSystemNo(templateInfo.getSystemNo());
			}
			return taskView;
		}
		return null;
	}

	@Override
	public List<ActHiComment> getApprovedOpinion(String instanceId) {
		return getApprovedOpinion(instanceId,"1");
	}
	
	@Override
	public List<ActHiComment> getApprovedOpinion(String instanceId, String type) {
		if (!StringUtils.isEmpty(instanceId)) {
			List<Comment> commentList = taskService.getProcessInstanceComments(instanceId, type);
			List<ActHiComment> resultList = new ArrayList<>();
			for (Comment comment : commentList) {
				ActHiComment actHiComment = new ActHiComment();
				actHiComment.setTime(comment.getTime());
				actHiComment.setUserId(comment.getUserId());
				actHiComment.setMessage(comment.getFullMessage());
				actHiComment.setTaskId(comment.getTaskId());
				resultList.add(actHiComment);
			}
			Collections.sort(resultList, new Comparator<ActHiComment>() {

				@Override
				public int compare(ActHiComment o1, ActHiComment o2) {
					return o2.getTime().compareTo(o1.getTime());
				}
				
			});
			
			return resultList;

		}
		return null;
	}

	/**
	 * 获得当前节点所能到达的节点信息
	 */
	@Override
	public List<JSONObject> getNextFlowNode(String taskId) {
		List<JSONObject> nextFolwNodes = new ArrayList<>();
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
		 // 当前审批节点
	    String crruentActivityId = ee.getActivityId();
	    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
	    FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
	    // 输出连线
	    List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
	    //获得所有可达到的节点
	    getNextFlowNode(nextFolwNodes, outFlows);
	    return nextFolwNodes;
	}
	
	
	@Override
	public String getCurrentNode(String taskId) {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
		 // 当前审批节点
	    return ee.getActivityId();
	}
	
	private void getNextFlowNode(List<JSONObject> nextFolwNodes,List<SequenceFlow> outFlows) {
		for (SequenceFlow sequenceFlow : outFlows) {
	    	JSONObject flow = new JSONObject();
	    	FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
	    	if (targetFlow instanceof UserTask) {
	    		flow.put("itemValue", targetFlow.getId());
	    		flow.put("itemText", targetFlow.getName());
	    		nextFolwNodes.add(flow);
	    	}else if(targetFlow instanceof EndEvent) {
	    		flow.put("itemValue", FlowConstants.flow_end_value);
	    		flow.put("itemText", FlowConstants.flow_end_text);
	    		nextFolwNodes.add(flow);
	    	}else if (targetFlow instanceof Gateway) {
	    		getNextFlowNode(nextFolwNodes, ((Gateway) targetFlow).getOutgoingFlows());
            }
	    }

	}

	@Override
	public void setApprovedOpinion(List<ActHiComment> options) {
		hiCommentService.updateBatchById(options);
		
	}

	@Override
	public List<ActHiComment> getApprovedOpinionNew(String instanceId) {
		QueryWrapper<ActHiComment> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(ActHiComment::getProcInstId, instanceId);
		queryWrapper.lambda().eq(ActHiComment::getType, "1");
		queryWrapper.lambda().orderByDesc(ActHiComment::getTime);
		return hiCommentService.list(queryWrapper);
	}

	

}
